/*
 *    This file is part of SSHTunneler.
 *
 *    Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
 *
 *    SSHTunneler is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    SSHTunneler is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with SSHTunneler.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package sshtunneler.client.gui;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;

import sshtunneler.client.SSHTunnelerApp;
import sshtunneler.client.data.Config;
import sshtunneler.client.data.TunnelerServer;
import sshtunneler.client.data.TunnelerServerContainer;
import sshtunneler.client.data.TunnelerServerTunnelFile;
import sshtunneler.client.ssh.SSHConnection;
import sshtunneler.client.ssh.SSHConnectionContainer;
import sshtunneler.library.Server;
import sshtunneler.server_tunnel.gui.AddServer;
import sshtunneler.server_tunnel.gui.AddTunnel;
import sshtunneler.server_tunnel.tree.GenericServerTunnelTree;
import sshtunneler.server_tunnel.tree.ServerTunnelRootNode;
import sshtunneler.tools.ToolsManager;

public class ServerTunnelTree extends GenericServerTunnelTree implements
		ActionListener {
	/** Server menu **/
	private JMenuItem server_menu_edit;
	private JMenuItem server_menu_connect;
	private JMenuItem server_menu_disconnect;
	private JMenuItem server_menu_add_tunnel;
	private JMenuItem server_menu_establish_all_tunnels;
	private JMenuItem server_menu_remove;

	/** Tunnel menu **/
	private JMenuItem tunnel_menu_establish;
	private JMenuItem tunnel_menu_edit;
	private JMenuItem tunnel_menu_destroy;
	private JMenuItem tunnel_menu_remove;

	/** Root menu **/
	private JMenuItem root_menu_add_server;

	/** Real Tree **/
	private ServerTunnelRootNode root;

	public ServerTunnelTree() {
		this.root = new ServerTunnelRootNode(this, TunnelerServerContainer.inst);

		this.server_menu_connect = new JMenuItem("Connect");
		this.server_menu_disconnect = new JMenuItem("Disconnect");
		this.server_menu_add_tunnel = new JMenuItem("Add tunnel");
		this.server_menu_establish_all_tunnels = new JMenuItem(
				"Establish all tunnels");
		this.server_menu_remove = new JMenuItem("Remove this server");
		this.server_menu_edit = new JMenuItem("Edit");
		this.tunnel_menu_establish = new JMenuItem("Open");
		this.tunnel_menu_destroy = new JMenuItem("Close");
		this.tunnel_menu_remove = new JMenuItem("Remove");
		this.tunnel_menu_edit = new JMenuItem("Edit");
		this.root_menu_add_server = new JMenuItem("Add server");

		this.tunnel_menu_establish.addActionListener(this);
		this.tunnel_menu_destroy.addActionListener(this);
		this.tunnel_menu_remove.addActionListener(this);
		this.tunnel_menu_edit.addActionListener(this);
		this.server_menu_connect.addActionListener(this);
		this.server_menu_disconnect.addActionListener(this);
		this.server_menu_add_tunnel.addActionListener(this);
		this.server_menu_establish_all_tunnels.addActionListener(this);
		this.server_menu_remove.addActionListener(this);
		this.server_menu_edit.addActionListener(this);
		this.root_menu_add_server.addActionListener(this);
	}

	@Override
	public JPopupMenu get_root_menu() {
		JPopupMenu popup = new JPopupMenu();

		popup.add(this.root_menu_add_server);

		return popup;
	}

	@Override
	public JPopupMenu get_server_menu() {
		JPopupMenu popup = new JPopupMenu();
		boolean connected = SSHConnectionContainer.inst.hasConnectionTo(this
				.getSelected_server());

		if (connected) {
			popup.add(this.server_menu_disconnect);
			popup.addSeparator();
			popup.add(this.server_menu_establish_all_tunnels);
		} else {
			popup.add(this.server_menu_edit);
			popup.addSeparator();
			popup.add(this.server_menu_connect);
		}

		popup.addSeparator();
		popup.add(this.server_menu_add_tunnel);
		popup.addSeparator();
		popup.add(this.server_menu_remove);

		return popup;
	}

	@Override
	public JPopupMenu get_tunnel_menu() {
		JPopupMenu popup = new JPopupMenu();
		boolean server_connected = false;
		boolean tunnel_connected = false;
		SSHConnection conn = SSHConnectionContainer.inst.getConnectionTo(this
				.getSelected_server());

		if (conn != null) {
			server_connected = true;
			if (conn.tunnel_is_established(this.getSelected_tunnel())) {
				tunnel_connected = true;
				popup.add(this.tunnel_menu_destroy);

			} else {
				popup.add(this.tunnel_menu_establish);
			}
			popup.addSeparator();
		}

		popup.add(this.tunnel_menu_edit);
		popup.addSeparator();
		popup.add(ToolsManager.inst.get_tunnel_tools_menu(this
				.getSelected_server(), this.getSelected_tunnel(),
				server_connected, tunnel_connected, this));
		popup.addSeparator();
		popup.add(this.tunnel_menu_remove);

		return popup;
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource().equals(this.server_menu_connect)) {
			SSHConnectionContainer.inst.connectTo(this.getSelected_server());
		} else if (e.getSource().equals(this.server_menu_disconnect)) {
			SSHConnectionContainer.inst.closeConnectionTo(this
					.getSelected_server());
		} else if (e.getSource().equals(this.server_menu_add_tunnel)) {
			JFrame mainFrame = SSHTunnelerApp.getApplication().getMainFrame();
			AddTunnel gui = new AddTunnel(mainFrame, this.getSelected_server(),
					null, this);
			gui.setLocationRelativeTo(mainFrame);
			SSHTunnelerApp.getApplication().show(gui);
			(SSHTunnelerApp.getApplication().getMainFrame()).refreshNode(this
					.getSelected_node());
		} else if (e.getSource().equals(this.server_menu_remove)) {
			SSHConnection conn = SSHConnectionContainer.inst
					.getConnectionTo(this.getSelected_server());
			if (conn != null) {
				if (JOptionPane
						.showConfirmDialog(
								null,
								"A connection to this server is established. Disconnect?",
								"Continue?", JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
					return;
				}
				SSHConnectionContainer.inst.closeConnectionTo(this
						.getSelected_server());
			}

			this.getSelected_node().removeFromParent();
			TunnelerServerContainer.inst.removeServer((TunnelerServer) this
					.getSelected_server());
			if (Config.auto_save_servers_and_tunnel) {
				TunnelerServerTunnelFile.inst.auto_save();
			}
		} else if (e.getSource().equals(this.server_menu_establish_all_tunnels)) {
			SSHConnectionContainer.inst.getConnectionTo(
					this.getSelected_server()).establishAllTunnels();
		} else if (e.getSource().equals(this.server_menu_edit)) {

			JFrame mainFrame = SSHTunnelerApp.getApplication().getMainFrame();
			AddServer gui = new AddServer(mainFrame, this.getSelected_server(),
					this);
			gui.setLocationRelativeTo(mainFrame);
			SSHTunnelerApp.getApplication().show(gui);

			SSHTunnelerApp.getApplication().getMainFrame().refreshNode(
					this.getSelected_node());
		} else if (e.getSource().equals(this.root_menu_add_server)) {
			JFrame mainFrame = SSHTunnelerApp.getApplication().getMainFrame();
			AddServer gui = new AddServer(mainFrame, null, this);
			gui.setLocationRelativeTo(mainFrame);
			SSHTunnelerApp.getApplication().show(gui);

			(SSHTunnelerApp.getApplication().getMainFrame()).refreshNode(this
					.getSelected_node());
		} else if (e.getSource().equals(this.tunnel_menu_establish)) {
			SSHConnection conn = SSHConnectionContainer.inst
					.getConnectionTo(this.getSelected_server());
			if (conn.tunnel_is_established(this.getSelected_tunnel())) {
				return;
			}
			conn.establishTunnel(this.getSelected_tunnel());
		} else if (e.getSource().equals(this.tunnel_menu_destroy)) {
			SSHConnection conn = SSHConnectionContainer.inst
					.getConnectionTo(this.getSelected_server());
			if (!conn.tunnel_is_established(this.getSelected_tunnel())) {
				return;
			}
			conn.destroyTunnel(this.getSelected_tunnel());
		} else if (e.getSource().equals(this.tunnel_menu_remove)) {
			SSHConnection conn = SSHConnectionContainer.inst
					.getConnectionTo(this.getSelected_server());
			if (conn != null
					&& conn.tunnel_is_established(this.getSelected_tunnel())) {
				if (JOptionPane.showConfirmDialog(null,
						"This tunnel is established ... destroy?", "Continue?",
						JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION) {
					return;
				}
				conn.destroyTunnel(this.getSelected_tunnel());
			}

			this.getSelected_node().removeFromParent();
			this.getSelected_server().removeTunnel(this.getSelected_tunnel());
			if (Config.auto_save_servers_and_tunnel) {
				TunnelerServerTunnelFile.inst.auto_save();
			}
		} else if (e.getSource().equals(this.tunnel_menu_edit)) {
			JFrame mainFrame = SSHTunnelerApp.getApplication().getMainFrame();
			AddTunnel gui = new AddTunnel(mainFrame, this.getSelected_server(),
					this.getSelected_tunnel(), this);
			gui.setLocationRelativeTo(mainFrame);
			SSHTunnelerApp.getApplication().show(gui);
			(SSHTunnelerApp.getApplication().getMainFrame()).refreshNode(this
					.getSelected_node());
		} else if (e.getSource() instanceof JMenuItem) {
			ToolsManager.inst.process_event(e.getSource());
		}
	}

	public ServerTunnelRootNode getRoot() {
		return this.root;
	}

	@Override
	public Server create_server(String username, String hostname, int port) {
		TunnelerServer newServer = new TunnelerServer(username, hostname, port);
		TunnelerServerContainer.inst.addServer(newServer);
		return newServer;
	}

	@Override
	public void process_server_action(boolean added, boolean deleted,
			boolean modified) {
		if (Config.auto_save_servers_and_tunnel) {
			TunnelerServerTunnelFile.inst.auto_save();
		}
	}

	@Override
	public void process_tunnel_action(boolean added, boolean deleted,
			boolean modified) {
		if (Config.auto_save_servers_and_tunnel) {
			TunnelerServerTunnelFile.inst.auto_save();
		}
	}
}
